
import * as vscode from "vscode"
import {languages, CompletionItem} from "vscode"
import { readFileSync } from "fs";
import * as child_process from "child_process"

//注册命令
vscode.commands.registerCommand("lucomplete.config",()=>{
    console.log("xxxxxxxxxxxxxxxxx");
});

//获得值
function getConf():vscode.WorkspaceConfiguration{
    let conf = vscode.workspace.getConfiguration("lucomplete")
    return conf;
}

function pushArgs(args:string[],name){
    let conf = getConf();
    let as:string[] = conf.get(name);
    as.forEach((v,k)=>{
        args.push(v);
    });
}

function getValue(name):any{
    let conf = getConf();
    return conf.get(name);
}

/*
创建补全
需要继承CompletionItemProvider接口
重写两个方法

*/


class Completion implements vscode.CompletionItemProvider{
    provideCompletionItems(document: vscode.TextDocument, 
        position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext):  vscode.ProviderResult<vscode.CompletionList>
    {
        let list:Array<vscode.CompletionItem> = new Array<vscode.CompletionItem>();
        let v = new vscode.CompletionItem("string.find");

        

            let text =document.getText(new vscode.Range(new vscode.Position(0,0),position));
            let line = document.lineAt(position).text;
            let var_name;
            line.replace(/^[^.\w]*(\w+)[\.:]\w*$/g,(s,v)=>{
                var_name = v;
                return "";
            });
            if(var_name===undefined){
                return new vscode.CompletionList(list);
            }
            let typecast = [];
            text.replace(/((\w+)\s*=)*\s*cast\s*\(\s*\"*\'*(\w+)\"*\'*\s*(,\s*(\w+)\s*)*\)/g,(s,n1,lvar,typ,n2,arg)=>{
                if((var_name==lvar) || (var_name==arg)){
                    typecast.push({
                        var:lvar,
                        type:typ,
                        rvalue:arg,
                    });
                }
                return "";
            });


            
            let findType = {};
            typecast.forEach((v,k)=>{  findType[v.type] = true;});
            return vscode.workspace.findFiles("**/*.lua").then((files)=>{
                files.forEach((file,i)=>{
                    //遍历工作区文件夹文件
                    //let regxp = new RegExp("","i");
                    let regexp = /(\w+)\s*:\s*(\w+)/g;
                    let text = readFileSync(file.fsPath).toString();

                    //匹配 type:field
                    text.replace(regexp,(s,typ,field)=>{
                        if(findType[typ]===undefined){
                        }
                        else{
                            list.push(new vscode.CompletionItem(field));
                        }
                        return "";
                    });
                });
                let complelist = new vscode.CompletionList(list);
                return complelist;
            })
    }
    resolveCompletionItem?(item: vscode.CompletionItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CompletionItem>{
        return item;
    }
}

let Exec:child_process.ChildProcess;
let ExecInited = false;

class CXXCompletion implements vscode.CompletionItemProvider{
    provideCompletionItems(document: vscode.TextDocument, 
        position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext):  vscode.ProviderResult<vscode.CompletionList>
    {
        let path = document.uri.fsPath;
        let stdin;
        let stdout;
        let out = "";
        let loop = true;
        
        if(!ExecInited){
            let args:string[] = [];
            args.push(getValue("script"));
            let execpath = getValue("executable");
            Exec = child_process.spawn(execpath,args);
            Exec.on("error",(err)=>{
                console.log(err);
            })
            if(Exec.pid==null || Exec.pid==undefined){
                //启动进程失败
                return new vscode.CompletionList();
            }
            Exec.stdin.write("|||cfile\n");
            Exec.stdin.write(path+"\n");
            Exec.stdin.write("|||init_clang\n");
            Exec.stdout.setEncoding("utf-8");
            
            ExecInited=true;
        }

        return new Promise((resolve)=>{
            let callback = (data)=>{
                out = out + data;
                loop = false;
                let ret = data.search("!@!");
                if(ret>0){
                    resolve(out)
                }
                Exec.stdout.once("data",callback);
            }
            Exec.stdout.once("data",callback);


            //设置当前行和列
            Exec.stdin.write("|||setline\n");
            Exec.stdin.write((position.line+1).toString()+"\n");
            Exec.stdin.write("|||setcol\n");
            Exec.stdin.write((position.character+1).toString()+"\n");

            //设置当前缓存数据
            let text = document.getText();
            let find = text.match(/\n/g)
            let len = !find?0:find.length+1;
            Exec.stdin.write("|||add_bufferLines\n");
            Exec.stdin.write(len.toString()+"\n");
            Exec.stdin.write(text+"\n");

            Exec.stdin.write("|||completion\n");


        }).then((data:string)=>{
            let clist:Array<CompletionItem> = new Array<CompletionItem>();
            // //简单型匹配
            // data.replace(/COMPLETION:\s*(\w+)/g,(s,n)=>{
            //     let item = new CompletionItem(n);
            //     clist.push(item);
            //     return "";  
            // });


            //复杂型匹配
            data.replace(/COMPLETION:\s*(\w+)\s*:*\s*(\[#(\w+)#])?(\w+)?(\((<.+>,?)\))*/g,(s,n,t,typ,name,arg,arg2)=>{
                let label = n;
                let insert = n;  //
                let item = new CompletionItem(label);

                //快照?
                let sni = new vscode.SnippetString(label);


                item.label = n;
                //console.log(11,n,t,typ,name,arg,arg2);
                
                if(null==arg2){
                    //非函数
                    if(typ!=null){
                        item.kind = vscode.CompletionItemKind.Field;
                    }
                }
                else{
                    item.kind = vscode.CompletionItemKind.Function;
                    insert += "("
                    label += "  " + typ + "(";
                    let cma = '';
                    arg2.replace(/<#((\w+\s)*\w+)\s*(\*?\w+)#>/g,(s,typ,cst,name)=>{
                        //console.log(typ,name);
                        label+= cma + typ + " " + name;
                        cma = ',';
                        return "";
                    });
                }
                
                item.insertText = n;
                item.detail = label;
                clist.push(item);
                return "";
            });
            let range = document.getWordRangeAtPosition(position,/\w+\s*/g);
            return new vscode.CompletionList(clist);
        });
    }
    resolveCompletionItem?(item: vscode.CompletionItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CompletionItem>{
        
        return item;
    }
}

//
class SignatureHelpProvider implements vscode.SignatureHelpProvider{
    provideSignatureHelp(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult<vscode.SignatureHelp>{
        let text = document.getText(new vscode.Range(new vscode.Position(0,0),position));
        let len = text.length-1;
        let rparenthesis = 0; //
        let paramIdx = 0;    //参数索引
        let out = "";
        while(len>0){
            let c = text[len];
            if(c=='('){
                if(rparenthesis<=0){
                    break;
                }
                rparenthesis--;
            }
            else if(c==','){
                if(rparenthesis<=0){
                    paramIdx ++;
                }
            }
            else if(c==')'){
                rparenthesis++;
            }
            len --;
        }
        let pos = document.positionAt(len);
        let range = document.getWordRangeAtPosition(pos,/\w+\s*/);
        let range_text = document.getText(range);
        let word = range_text;
        let space = range_text.search(/\s/i);
        let line = range.end.line;
        let col = range.end.character;
        if(space>0){
            col -= space;
            word = range_text.substr(1,space);
        }
        text = document.getText();



        return new Promise((resolve)=>{
            let callback = (data)=>{
                out = out + data;
                let ret = data.search("!@!");
                if(ret>0){
                    resolve(out)
                }
                Exec.stdout.once("data",callback);
            }
            Exec.stdout.once("data",callback);


            //设置当前行和列
            Exec.stdin.write("|||setline\n");
            Exec.stdin.write((line+1).toString()+"\n");
            Exec.stdin.write("|||setcol\n");
            Exec.stdin.write((col+1).toString()+"\n");

            //设置当前缓存数据
            let text = document.getText();
            let find = text.match(/\n/g)
            let len = !find?0:find.length+1;
            Exec.stdin.write("|||add_bufferLines\n");
            Exec.stdin.write(len.toString()+"\n");
            Exec.stdin.write(text+"\n");

            Exec.stdin.write("|||completion\n");

        }).then((data:string)=>{
            let isfunc = false;
            let label = "";
            let a:vscode.SignatureHelp;
            data.replace(/COMPLETION:\s*(\w+)\s*:\s*(\[#(\w+)#])?(\w+)?(\((<.+>,?)\))*/g,(s,n,t,typ,name,arg,arg2)=>{
                if(name==word){
                    if(null==arg2){
                        //非函数
                        if(typ!=null){
                        }
                    }
                    else{
                        isfunc = true;
                        let cma = '';
                        a = new vscode.SignatureHelp();
                        let info = new vscode.SignatureInformation(name);
                        
                        a.activeParameter = paramIdx;
                        a.activeSignature = 0;
                        a.signatures.push(info);
                        arg2.replace(/<#((\w+\s)*\w+)\s*(\*?\w+)#>/g,(s,typ,cst,name)=>{
                            let param = new vscode.ParameterInformation(typ);
                            info.parameters.push(param);
                            label+= cma + typ + " ";
                            cma = ',';
                            return "";
                        });
                        info.label = label;
                    }
                }
                return "";
            });
            if(isfunc){
                return a;
            }
            return null;
        });
    }
}


//语言注册
const lang_mode : vscode.DocumentSelector = [
    { language: "lua", scheme: "file" },
];

const c_lan_mode : vscode.DocumentSelector=[
    {language:"c",scheme:"file"},
    {language:"cpp",scheme:"file"},
];


languages.registerSignatureHelpProvider(lang_mode,new SignatureHelpProvider(),",");
languages.registerSignatureHelpProvider(c_lan_mode,new SignatureHelpProvider(),"(",",");

languages.registerCompletionItemProvider(lang_mode,new Completion(),".",":");
languages.registerCompletionItemProvider(c_lan_mode,new CXXCompletion(),".",">");


